package part11singleton;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * @description: 单实例防止反射破坏，但是再次被破坏
 * @author: zhang hang
 * @date: 2024/3/24 15:49.
 * @version: 1.0
 */
public class SingletonTest07 {

    private static boolean flag = false;

    private volatile static SingletonTest07 instance;

    private SingletonTest07() {
        synchronized (SingletonTest07.class) {
            if (!flag) {
                flag = true;
            } else {
                throw new RuntimeException("不要试图使用反射破坏异常");
            }
        }
    }

    public static SingletonTest07 getInstance() {
        if (instance == null) {
            synchronized (SingletonTest07.class) {
                if (instance == null) {
                    instance = new SingletonTest07();
                }
            }
        }
        return instance;
    }

    // 防止反射破坏单例模式
    public static void main01(String[] args) {
        try {
            Constructor<SingletonTest07> declaredConstructor = SingletonTest07.class.getDeclaredConstructor(null);
            declaredConstructor.setAccessible(true);
            SingletonTest07 lazyMan1 = declaredConstructor.newInstance();
            SingletonTest07 lazyMan2 = declaredConstructor.newInstance();
            System.out.println(lazyMan1.hashCode());
            System.out.println(lazyMan2.hashCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 反射再次破坏单例模式
    public static void main(String[] args) {
        try {
            Constructor<SingletonTest07> declaredConstructor = SingletonTest07.class.getDeclaredConstructor(null);
            Field field = SingletonTest07.class.getDeclaredField("flag");
            field.setAccessible(true);
            declaredConstructor.setAccessible(true);
            SingletonTest07 lazyMan1 = declaredConstructor.newInstance();
            field.set(lazyMan1, false);

            SingletonTest07 lazyMan2 = declaredConstructor.newInstance();
            System.out.println(lazyMan1.hashCode());
            System.out.println(lazyMan2.hashCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
